﻿using Als.Utils.Data;
using Als.Utils.String;
using System;
using System.Runtime.Caching;

namespace Als.Utils.Net
{
    /// <summary>
    /// Winform和Wpf中构建缓存
    /// </summary>
    public class MemoryCacheHelper : ICache
    {
        private static readonly ObjectCache Cache;

        static MemoryCacheHelper()
        {
            Cache = MemoryCache.Default;
        }

        /// <summary>
        /// 设置过期时间
        /// 小于等于0不过期，单位为秒
        /// </summary>
        /// <param name="seconds">过期时间秒</param>
        /// <returns></returns>
        private static DateTimeOffset GetTimeOffset(int seconds)
        {
            return seconds <= 0 ? DateTimeOffset.MaxValue : DateTimeOffset.Now.AddSeconds(seconds);
        }

        /// <summary>
        /// 添加缓存
        /// 键-值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public bool Add(string key, string value, int seconds = 0)
        {
            return !value.IsNullOrEmpty() && Cache.Add(key, value, GetTimeOffset(seconds));
        }

        /// <summary>
        /// 添加缓存
        /// 键-对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="value">对象</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public bool Add<T>(string key, T value, int seconds = 0) where T : class, new()
        {
            return Add(key, value.ToJson(), seconds);
        }

        /// <summary>
        /// 修改缓存
        /// 键-值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public bool Set(string key, string value, int seconds = 0)
        {
            if (value.IsNullOrEmpty())
                return false;

            Cache.Set(key, value, GetTimeOffset(seconds));
            return true;
        }

        /// <summary>
        /// 修改缓存
        /// 键-对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="value">对象</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, int seconds = 0) where T : class, new()
        {
            if (value.IsNull())
                return false;

            Set(key, value.ToJson(), seconds);
            return true;
        }

        /// <summary>
        /// 获取缓存
        /// 键-值
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public string Get(string key)
        {
            return Get<string>(key);
        }

        /// <summary>
        /// 获取缓存
        /// 键-对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">键</param>
        /// <returns></returns>
        public T Get<T>(string key) where T : class
        {
            return Cache.Get(key) as T;
        }

        /// <summary>
        /// 添加并获取缓存
        /// 键-值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="aquire">方法体</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public string GetOrAdd(string key, Func<string> aquire, int seconds = 0)
        {
            var data = Get(key);
            if (!data.IsNullOrEmpty())
                return data;

            data = aquire();
            if (data.IsNullOrEmpty())
                return null;

            Cache.Add(key, data, GetTimeOffset(seconds));
            return data;
        }

        /// <summary>
        /// 添加并获取缓存
        /// 键-对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="aquire">方法体</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public T GetOrAdd<T>(string key, Func<T> aquire, int seconds = 0) where T : class, new()
        {
            var data = Cache.Get(key) as T;
            if (data.IsNotNull())
                return data;

            data = aquire();
            if (data.IsNull())
                return null;

            Cache.Add(key, data, GetTimeOffset(seconds));
            return data;
        }

        /// <summary>
        /// 修改并获取缓存
        /// 键-值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="aquire">方法体</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public string GetOrSet(string key, Func<string> aquire, int seconds = 0)
        {
            var data = Get(key);
            if (!data.IsNullOrEmpty())
                return data;

            data = aquire();
            if (data.IsNullOrEmpty())
                return null;

            Set(key, data, seconds);
            return data;
        }

        /// <summary>
        /// 修改并获取缓存
        /// 键-对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="aquire">方法体</param>
        /// <param name="seconds">过期时间，默认不过期</param>
        /// <returns></returns>
        public T GetOrSet<T>(string key, Func<T> aquire, int seconds = 0) where T : class, new()
        {
            var data = Get<T>(key);
            if (data.IsNotNull())
                return data;

            data = aquire();
            if (data.IsNull())
                return null;

            Set(key, data, seconds);
            return data;
        }

        /// <summary>
        /// 是否包含指定缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public bool Contains(string key)
        {
            return Cache.Contains(key);
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            return Cache.Remove(key) != null;
        }


    }
}
